import { is2DArray, deepClone, colorLuminance } from '@/utils/index';
import { color } from 'echarts';

/**
 * @description: 生成3D饼图配置方法
 * @param {Object} option 配置对象
 * @param {Array} option.pieData 饼图数据
 * @param {Number} option.internalRatio 内径比 当该值等于 0 时，为普通饼图 （0~1之间的浮点数）
 * @param {Number} option.aspectRatio 长宽比
 */
const pie_3D = ({
  pieData = [],
  color = [
    '#66a6ff',
    '#5470c6',
    '#91cc75',
    '#fac858',
    '#ee6666',
    '#73c0de',
    '#3ba272',
    '#fc8452',
    '#9a60b4',
    '#ea7ccc',
  ],
  unit = '',
  internalRatio = undefined,
  aspectRatio = 1,
  legend = true,
  legendPosition = 'top',
  showSeriesLabel = false,
  showPercent = true,
  isSelected = false,
  isHovered = false,
  isNegative = false, // 是否负数
}) => {
  let series = [];
  // pieData为二维数组时,设置多个series
  if (is2DArray(pieData)) {
    let colorIndex = 0;
    pieData.forEach((dataArr, index) => {
      // 饼图数据合计值
      const data_total = dataArr.reduce((pre, item) => (pre += item.value), 0);
      dataArr.forEach((item) => {
        item.itemStyle = {
          opacity: 1,
          color: color[colorIndex],
        };
        item.percent = item.value === 0 ? 0 : Number(((item.value / data_total) * 100).toFixed(2));
        colorIndex++;
      });
      const dataArrSeries = getPie3D({
        pieData: dataArr,
        internalRatio: Array.isArray(internalRatio) ? internalRatio[index] : internalRatio,
        aspectRatio: Array.isArray(aspectRatio) ? aspectRatio[index] : aspectRatio,
        isSelected,
        isHovered,
        showSeriesLabel,
      });
      series = [...series, ...dataArrSeries];
    });
    // pieData为普通数组时,设置一个series
  } else {
    // 饼图数据合计值
    const data_total = pieData.reduce((pre, item) => (pre += item.value), 0);
    // 设置颜色、百分比
    pieData.forEach((item, index) => {
      item.itemStyle = {
        opacity: 1,
        color: color[index],
      };
      item.percent = item.value === 0 ? 0 : Number(((item.value / data_total) * 100).toFixed(2));
    });
    series = getPie3D({ pieData, internalRatio, aspectRatio, isSelected, isHovered, showSeriesLabel });
  }
  const legendData = series.filter((item) => {
    if (item.name && item.name !== 'mouseoutSeries') {
      return item.name;
    }
  });
  const defaultConfig = {
    legend: legend && {
      orient: ['top', 'bottom'].includes(legendPosition) ? 'horizontal' : 'vertical',
      itemWidth: 35,
      itemWHeight: 10,
      top: legendPosition == 'top' ? '0' : legendPosition == 'bottom' ? null : 'center',
      left: legendPosition == 'left' ? '3%' : legendPosition == 'right' ? null : 'center',
      right: legendPosition == 'right' ? '3%' : legendPosition == 'left' ? null : 'center',
      bottom: legendPosition == 'bottom' ? '0' : legendPosition == 'top' ? null : 'center',
      data: legendData,
      formatter: function (params) {
        const seriesData = pieData.find((item) => item.name == params);
        return `${params}  ${seriesData.value} ${unit}`;
      },
      textStyle: {
        fontSize: 14,
        color: '#00ffff',
        rich: {
          underline: {
            width: 70,
            height: 0,
            borderWidth: 1,
            borderColor: '#00ffff',
          },
        },
      },
      itemGap: 15,
      selected: {},
      // selectedMode: false,
      tooltip: {
        show: true,
        confine: true,
        trigger: 'item',
        formatter: (params) => {
          const seriesData = pieData.find((item) => item.name == params.name);
          if (seriesData) {
            let content =
              `<span style="display:inline-block; margin-right:4px; border-radius:10px;` +
              `width:10px; height:10px; background-color:${seriesData.itemStyle.color};"></span>` +
              `${params.name}&nbsp;&nbsp;` +
              `<span style="font-weight:bold;">${isNegative ? '-' : ''}${seriesData.value} ${unit}</span>` +
              `<span>${showPercent ? `&nbsp;&nbsp;${seriesData.percent}%` : ''}</span>`;
            return content;
          }
        },
      },
    },
    tooltip: {
      confine: true,
      trigger: 'item',
      formatter: (params) => {
        if (params.seriesName && params.seriesName !== 'mouseoutSeries') {
          let content =
            `${params.marker}${params.seriesName}&nbsp;` +
            `<span style="font-weight:bold;">
            ${isNegative ? '-' : ''}${defaultConfig.series[params.seriesIndex].pieData.value} ${unit}</span>` +
            `<span>${
              showPercent ? `&nbsp;&nbsp;${defaultConfig.series[params.seriesIndex].pieData.percent}%` : ''
            }</span>`;
          return content;
        }
      },
    },
    xAxis3D: {
      show: false,
      // min: -1,
      // max: 1,
    },
    yAxis3D: {
      show: false,
      // min: -1,
      // max: 1,
    },
    zAxis3D: {
      show: false,
      min: -1,
      max: 1,
    },
    grid3D: {
      show: false,
      boxHeight: 8,
      top: legendPosition == 'top' ? '0' : legendPosition == 'bottom' ? '-15%' : '-10%',
      // bottom: '5',
      left: legendPosition == 'left' ? '12%' : legendPosition == 'right' ? '-12%' : 'auto',
      // bottom: '50%',
      viewControl: {
        // rotateSensitivity: 0,
        zoomSensitivity: 0,
        panSensitivity: 0,
        center: [0, 0, 0],
        distance: 120,
        alpha: 35,
        beta: -55,
      },
      postEffect: {
        //配置这项会出现锯齿，请自己去查看官方配置有办法解决
        enable: true,
        bloom: {
          enable: true,
          bloomIntensity: 0.1,
        },
        SSAO: {
          enable: true,
          quality: 'medium',
          radius: 2,
        },
      },
    },
    series: series,
  };

  const opt = deepClone(defaultConfig);
  return opt;
};

/**
 * @description: 生成3D饼图系列方法
 * @param {Object} option 配置对象
 * @param {Array} option.pieData 饼图数据
 * @param {Number} option.internalRatio 内径比 当该值等于 0 时，为普通饼图 （0~1之间的浮点数）
 * @param {Number} option.aspectRatio 长宽比
 */
const getPie3D = ({ pieData = [], internalRatio, aspectRatio, isSelected, isHovered, showSeriesLabel }) => {
  let series = [];
  let sumValue = 0;
  let startValue = 0;
  let endValue = 0;
  // 通过扇形内径/外径的值，换算出辅助参数 k（默认值 1/3）
  let k = typeof internalRatio !== 'undefined' ? (1 - internalRatio) / (1 + internalRatio) : 1 / 3;
  // 为每一个饼图数据，生成一个 series-surface 配置
  for (let i = 0; i < pieData.length; i++) {
    sumValue += pieData[i].value;
    let seriesItem = {
      name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
      type: 'surface',
      parametric: true,
      wireframe: { show: false },
      pieData: pieData[i],
      pieStatus: {
        selected: false,
        hovered: false,
        k: k,
      },
    };
    // 拼图数据itemStyle配置颜色和透明度
    if (typeof pieData[i].itemStyle != 'undefined') {
      let itemStyle = {};
      typeof pieData[i]?.itemStyle?.color != 'undefined' ? (itemStyle.color = pieData[i].itemStyle.color) : null;
      typeof pieData[i]?.itemStyle?.opacity != 'undefined' ? (itemStyle.opacity = pieData[i].itemStyle.opacity) : null;
      seriesItem.itemStyle = itemStyle;
    }
    series.push(seriesItem);
  }
  // 标签 label 系列
  let labelSeriesItem = {
    type: 'bar3D',
    barSize: [0.1, 0.1],
    data: [],
    label: {
      show: true,
      formatter: function (params) {
        // return `${params.name}\n${params.value[3]}`;
        return `${params.value[3]}`;
      },
      distance: 3,
      textStyle: {
        color: '#fff',
        fontSize: 18,
      },
      backgroundColor: 'transparent',
    },
  };
  // 使用上一次遍历时，计算出的数据和 sumValue，调用 getParametricEquation 函数，
  // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation，也就是实现每一个扇形。
  series.forEach((seriesItem, index) => {
    endValue = startValue + seriesItem.pieData.value;
    seriesItem.pieData.startRatio = sumValue ? startValue / sumValue : 0;
    seriesItem.pieData.endRatio = sumValue ? endValue / sumValue : 0;
    seriesItem.parametricEquation = getParametricEquation({
      startRatio: seriesItem.pieData.startRatio,
      endRatio: seriesItem.pieData.endRatio,
      isSelected: isSelected,
      isHovered: isHovered,
      k,
      aspectRatio,
      h: seriesItem.pieData.value,
    });
    startValue = endValue;
    // 判断增加 label 效果
    // if (pieData[index].label && pieData[index].label.show) {
    if (showSeriesLabel) {
      let labelRadian = (seriesItem.pieData.startRatio + seriesItem.pieData.endRatio) * Math.PI;
      labelSeriesItem.data.push({
        name: seriesItem.name,
        value: [Math.cos(labelRadian), Math.sin(labelRadian), 1.2, seriesItem.pieData.value],
        itemStyle: {
          opacity: 1,
        },
      });
    }
  });
  // 将 labelSeriesItem 添加进系列中
  series.push(labelSeriesItem);
  // 补充一个透明的圆环，用于支撑高亮功能的近似实现。
  series.push({
    name: 'mouseoutSeries',
    type: 'surface',
    parametric: true,
    wireframe: {
      show: false,
    },
    itemStyle: {
      opacity: 0,
    },
    parametricEquation: {
      u: {
        min: 0,
        max: Math.PI * 2,
        step: Math.PI / 20,
      },
      v: {
        min: 0,
        max: Math.PI,
        step: Math.PI / 20,
      },
      x: function (u, v) {
        return Math.sin(v) * Math.sin(u) + Math.sin(u);
      },
      y: function (u, v) {
        return Math.sin(v) * Math.cos(u) + Math.cos(u);
      },
      z: function (u, v) {
        return Math.cos(v) > 0 ? 0.1 : -0.1;
      },
    },
  });
  return series;
};
/**
 * @description: 生成扇形的曲面参数方程，用于 series-surface.parametricEquation
 * @param {Object} object 参数对象
 * @param {Number} object.startRatio 扇形起始比例 取值区间 [0, endRatio)
 * @param {Number} object.endRatio 扇形结束比例 取值区间 (startRatio, 1]
 * @param {Boolean} object.isSelected 是否开启选中效果 效果参照二维饼图选中效果（单选）
 * @param {Boolean} object.isHovered 是否开启放大高亮效果 效果接近二维饼图高亮（放大）效果（未能实现阴影）
 * @param {Number} object.k 通过扇形内径/外径的值，换算出辅助参数 k（默认值 1/3）
 * @param {Number} object.aspectRatio 长宽比
 * @param {Number} object.h 扇形高度比
 */
const getParametricEquation = ({ startRatio, endRatio, isSelected, isHovered, k, aspectRatio, h }) => {
  // 计算扇形弧度
  let midRatio = (startRatio + endRatio) / 2;
  let startRadian = startRatio * Math.PI * 2;
  let endRadian = endRatio * Math.PI * 2;
  let midRadian = midRatio * Math.PI * 2;
  // 如果只有一个扇形，则不实现选中效果。
  if (startRatio === 0 && endRatio === 1) isSelected = false;
  // 通过扇形内径/外径的值，换算出辅助参数 k（默认值 1/3）
  k = typeof k !== 'undefined' ? k : 1 / 3;
  // 计算选中效果分别在 x 轴、y 轴方向上的位移（未选中，则位移均为 0）
  let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
  let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
  // 计算高亮效果的放大比例（未高亮，则比例为 1）
  let hoverRate = isHovered ? 1.05 : 1;
  // 返回曲面参数方程
  return {
    u: {
      min: -Math.PI,
      max: Math.PI * 3,
      step: Math.PI / 32,
    },
    v: {
      min: 0,
      max: Math.PI * 2,
      step: Math.PI / 20,
    },
    x: function (u, v) {
      if (u < startRadian) {
        return offsetX + Math.cos(startRadian) * (aspectRatio + Math.cos(v) * k) * hoverRate;
      }
      if (u > endRadian) {
        return offsetX + Math.cos(endRadian) * (aspectRatio + Math.cos(v) * k) * hoverRate;
      }
      return offsetX + Math.cos(u) * (aspectRatio + Math.cos(v) * k) * hoverRate;
    },
    y: function (u, v) {
      if (u < startRadian) {
        return offsetY + Math.sin(startRadian) * (aspectRatio + Math.cos(v) * k) * hoverRate;
      }
      if (u > endRadian) {
        return offsetY + Math.sin(endRadian) * (aspectRatio + Math.cos(v) * k) * hoverRate;
      }
      return offsetY + Math.sin(u) * (aspectRatio + Math.cos(v) * k) * hoverRate;
    },
    z: function (u, v) {
      if (u < -Math.PI * 0.5) return Math.sin(u);
      if (u > Math.PI * 2.5) return Math.sin(u) * 2;
      return Math.sin(v) > 0 ? 1 * 2 : -1;
      // if (u > Math.PI * 2.5) return Math.sin(u) * h * 0.1;
      // return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
    },
  };
};

export default {
  pie_3D,
};
